///////////////////////////////////////////////////////////////////////////////
//
// lighthouse3D - 3D Software Library
//
// File: CObjects.cpp
//
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2003-2013 Marcus Reinhardt
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
///////////////////////////////////////////////////////////////////////////////
//
// You can find a copy of the GNU General Public License (gpl.txt) in the
// directory of the library.
//
///////////////////////////////////////////////////////////////////////////////
#include "CObjects.h"

///////////////////////////////////////////////////////////////////////////////
// CObjects::CObjects( ... )
///////////////////////////////////////////////////////////////////////////////
CObjects::CObjects()
{
  planeSelect = 0;
  planeSize = 30;

  cubeSize = 30;
  cubeTopLess = false;
  cubeBottomLess = false;

  pyramidSize = 30;
  
  cylinderHeight = 30;
  cylinderRadiusTop = 25;
  cylinderRadiusBottom = 25;
  cylinderCirclePoints = 40;
  
  coneHeight = 40;
  coneRadiusBottom = 15;
  coneCirclePoints = 50;

  sphereVCircles = 10;
  spherePoints = 50;
  sphereRadius = 30;
  
  simpleSurfaceSizeX = 32;
  simpleSurfaceSizeZ = 32;
  simpleSurfaceMultiplikator = 30;
  simpleSurfaceSeed = 13799;
  simpleSurfaceWaterLevel = 100;
  simpleSurfaceDeepWaterLevel = 100;
  simpleSurfaceSnowLevel = 200;
  simpleSurfaceBeachLevel = 105;
  simpleSurfaceSmoothLevel = 5;
  
  simpleSurfaceScaling = 1.0;
  
  simpleSurfaceWaterLevel = simpleSurfaceWaterLevel / simpleSurfaceScaling;
  simpleSurfaceDeepWaterLevel = simpleSurfaceDeepWaterLevel / simpleSurfaceScaling;
  simpleSurfaceSnowLevel = simpleSurfaceSnowLevel / simpleSurfaceScaling;
  simpleSurfaceBeachLevel = simpleSurfaceBeachLevel / simpleSurfaceScaling;

  heightMapSurfaceMultiplikator = 15;
  heightMapSurfaceMultiplikatorY = 1.5;
  heightMapSurfaceAutoBalance = 1;
}

///////////////////////////////////////////////////////////////////////////////
// CObjects::~CObjects( ... )
///////////////////////////////////////////////////////////////////////////////
CObjects::~CObjects()
{
  release();
}

///////////////////////////////////////////////////////////////////////////////
// CObjects::release( ... )
///////////////////////////////////////////////////////////////////////////////
void CObjects::release()
{
}

///////////////////////////////////////////////////////////////////////////////
// CObjects::createPlane( ... )
///////////////////////////////////////////////////////////////////////////////
// Creates a plane using the texture specified in texname
///////////////////////////////////////////////////////////////////////////////
bool CObjects::createPlane(CMeshStorage *s, const char *texname)
{
  TMeshVertex v;
  TMeshTriangle f;

  CMeshData *m = s->getMesh(s->getMeshCount()-1);
  
  if (m == NULL)
      return false;

  m->clear();

  if ( fileHandler.loadImageToTexture(texname, &t1) == false )
  {      
      return false;
  }

  s->addTex(t1);

  if (planeSelect == 0) {

     // xy-plane vertexes
     v.x = -planeSize;
     v.y = planeSize;
     v.z = 0;
     m->addVert(v);

     v.x = planeSize;
     v.y = planeSize;
     v.z = 0;
     m->addVert(v);

     v.x = -planeSize;
     v.y = -planeSize;
     v.z = 0;
     m->addVert(v);

     v.x = planeSize;
     v.y = -planeSize;
     v.z = 0;
     m->addVert(v);
  
     // face - 1st part
     f.v[0] = 0;
     f.v[1] = 1;
     f.v[2] = 2;
       f.ut[0] = 0;
     f.vt[0] = 0;
     f.ut[1] = 1;
     f.vt[1] = 0;
     f.ut[2] = 0;
     f.vt[2] = 1;
     f.texture = s->getTexCount()-1;
     m->addFace(f);

     // face - 2nd part
     f.v[0] = 1;
     f.v[1] = 3;
     f.v[2] = 2;
     f.ut[0] = 1;
     f.vt[0] = 0;
     f.ut[2] = 0;
     f.vt[2] = 1;
     f.ut[1] = 1;
     f.vt[1] = 1;
     f.texture = s->getTexCount()-1;
     m->addFace(f);
  }

  if (planeSelect == 1) {

     // yz-plane vertexes

     v.x = 0;
     v.y = planeSize;
     v.z = -planeSize;
     m->addVert(v);

     v.x = 0;
     v.y = planeSize;
     v.z = planeSize;
     m->addVert(v);

     v.x = 0;
     v.y = -planeSize;
     v.z = -planeSize;
     m->addVert(v);
  
     v.x = 0;
     v.y = -planeSize;
     v.z = planeSize;
     m->addVert(v);

     // face - 1st part
     f.v[0] = 0;
     f.v[1] = 1;
     f.v[2] = 2;
     f.ut[0] = 0;
     f.vt[0] = 0;
     f.ut[1] = 1;
     f.vt[1] = 0;
     f.ut[2] = 0;
     f.vt[2] = 1;
     f.texture = s->getTexCount()-1;
     m->addFace(f);

     // face - 2nd part
     f.v[0] = 1;
     f.v[1] = 3;
     f.v[2] = 2;
     f.ut[0] = 1;
     f.vt[0] = 0;
     f.ut[2] = 0;
     f.vt[2] = 1;
     f.ut[1] = 1;
     f.vt[1] = 1;
     f.texture = s->getTexCount()-1;
     m->addFace(f);
  }
  
  if (planeSelect == 2) {

     // xz-plane vertexes

     v.x = -planeSize;
     v.y = 0;
     v.z = planeSize;
     m->addVert(v);

     v.x = planeSize;
     v.y = 0;
     v.z = planeSize;
     m->addVert(v);

     v.x = -planeSize;
     v.y = 0;
     v.z = -planeSize;
     m->addVert(v);
  
     v.x = planeSize;
     v.y = 0;
     v.z = -planeSize;
     m->addVert(v);

     // top face - 1st part
     f.v[0] = 0;
     f.v[1] = 1;
     f.v[2] = 2;
     f.ut[0] = 0;
     f.vt[0] = 0;
     f.ut[1] = 1;
     f.vt[1] = 0;
     f.ut[2] = 0;
     f.vt[2] = 1;
     f.texture = s->getTexCount()-1;
     m->addFace(f);

     // top face - 2nd part
     f.v[0] = 1;
     f.v[1] = 3;
     f.v[2] = 2;
     f.ut[0] = 1;
     f.vt[0] = 0;
     f.ut[2] = 0;
     f.vt[2] = 1;
     f.ut[1] = 1;
     f.vt[1] = 1;
     f.texture = s->getTexCount()-1;
     m->addFace(f);

  }

  strcpy(m->m_name, "Textured Plane");

  return true;
}

///////////////////////////////////////////////////////////////////////////////
// CObjects::createPyramid( ... )
///////////////////////////////////////////////////////////////////////////////
// Creates a pyramid using the texture specified in texname
///////////////////////////////////////////////////////////////////////////////
bool CObjects::createPyramid(CMeshStorage *s, const char *texname)
{
  TMeshVertex v;
  TMeshTriangle f;

  CMeshData *m = s->getMesh(s->getMeshCount()-1);
  
  if (m == NULL)
      return false;

  m->clear();

  if ( fileHandler.loadImageToTexture(texname, &t1) == false )
  {      
      return false;
  }

  s->addTex(t1);

  // front face

  v.x = 0;
  v.y = pyramidSize;
  v.z = 0;
  m->addVert(v);

  v.x = pyramidSize;
  v.y = -pyramidSize;
  v.z = -pyramidSize;
  m->addVert(v);

  v.x = -pyramidSize;
  v.y = -pyramidSize;
  v.z = -pyramidSize;
  m->addVert(v);

  f.v[0] = 0;
  f.v[1] = 1;
  f.v[2] = 2;
  f.ut[0] = 0.5;
  f.vt[0] = 0;
  f.ut[1] = 1;
  f.vt[1] = 1;
  f.ut[2] = 0;
  f.vt[2] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);

  // back face

  v.x = 0;
  v.y = pyramidSize;
  v.z = 0;
  m->addVert(v);

  v.x = -pyramidSize;
  v.y = -pyramidSize;
  v.z = pyramidSize;
  m->addVert(v);

  v.x = pyramidSize;
  v.y = -pyramidSize;
  v.z = pyramidSize;
  m->addVert(v);

  f.v[0] = 3;
  f.v[1] = 4;
  f.v[2] = 5;
  f.ut[0] = 0.5;
  f.vt[0] = 0;
  f.ut[1] = 1;
  f.vt[1] = 1;
  f.ut[2] = 0;
  f.vt[2] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);

  // left face

  v.x = 0;
  v.y = pyramidSize;
  v.z = 0;
  m->addVert(v);

  v.x = -pyramidSize;
  v.y = -pyramidSize;
  v.z = -pyramidSize;
  m->addVert(v);

  v.x = -pyramidSize;
  v.y = -pyramidSize;
  v.z = pyramidSize;
  m->addVert(v);

  f.v[0] = 6;
  f.v[1] = 7;
  f.v[2] = 8;
  f.ut[0] = 0.5;
  f.vt[0] = 0;
  f.ut[2] = 0;
  f.vt[2] = 1;
  f.ut[1] = 1;
  f.vt[1] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);

  // right face

  v.x = 0;
  v.y = pyramidSize;
  v.z = 0;
  m->addVert(v);

  v.x = pyramidSize;
  v.y = -pyramidSize;
  v.z = pyramidSize;
  m->addVert(v);

  v.x = pyramidSize;
  v.y = -pyramidSize;
  v.z = -pyramidSize;
  m->addVert(v);

  f.v[0] = 9;
  f.v[1] = 10;
  f.v[2] = 11;
  f.ut[0] = 0.5;
  f.vt[0] = 0;
  f.ut[1] = 1;
  f.vt[1] = 1;
  f.ut[2] = 0;
  f.vt[2] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);

  strcpy(m->m_name, "Textured Pyramid");

  return true;
}

///////////////////////////////////////////////////////////////////////////////
// CObjects::createCube( ... )
///////////////////////////////////////////////////////////////////////////////
// Creates a cube using the texture specified in texname
///////////////////////////////////////////////////////////////////////////////
bool CObjects::createCube(CMeshStorage *s, const char *texname)
{
  TMeshVertex v;
  TMeshTriangle f;

  CMeshData *m = s->getMesh(s->getMeshCount()-1);

  if (m == NULL)
      return false;

  m->clear();

  if ( fileHandler.loadImageToTexture(texname, &t1) == false )
  {      
      return false;
  }

  s->addTex(t1);

  // front vertexes
  v.x = -cubeSize;
  v.y = cubeSize;
  v.z = -cubeSize;
  m->addVert(v);

  v.x = cubeSize;
  v.y = cubeSize;
  v.z = -cubeSize;
  m->addVert(v);

  v.x = -cubeSize;
  v.y = -cubeSize;
  v.z = -cubeSize;
  m->addVert(v);

  v.x = cubeSize;
  v.y = -cubeSize;
  v.z = -cubeSize;
  m->addVert(v);
  
  // front face - 1st part
  f.v[0] = 0;
  f.v[1] = 1;
  f.v[2] = 2;
  f.ut[0] = 0;
  f.vt[0] = 0;
  f.ut[1] = 1;
  f.vt[1] = 0;
  f.ut[2] = 0;
  f.vt[2] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);

  // front face - 2nd part
  f.v[0] = 1;
  f.v[1] = 3;
  f.v[2] = 2;
  f.ut[0] = 1;
  f.vt[0] = 0;
  f.ut[2] = 0;
  f.vt[2] = 1;
  f.ut[1] = 1;
  f.vt[1] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);

  // back vertexes

  v.x = cubeSize;
  v.y = cubeSize;
  v.z = cubeSize;
  m->addVert(v);

  v.x = -cubeSize;
  v.y = cubeSize;
  v.z = cubeSize;
  m->addVert(v);

  v.x = cubeSize;
  v.y = -cubeSize;
  v.z = cubeSize;
  m->addVert(v);
  
  v.x = -cubeSize;
  v.y = -cubeSize;
  v.z = cubeSize;
  m->addVert(v);

  // back face - 1st part
  f.v[0] = 4;
  f.v[1] = 5;
  f.v[2] = 6;
  f.ut[0] = 0;
  f.vt[0] = 0;
  f.ut[1] = 1;
  f.vt[1] = 0;
  f.ut[2] = 0;
  f.vt[2] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);

  // back face - 2nd part
  f.v[0] = 5;
  f.v[1] = 7;
  f.v[2] = 6;
  f.ut[0] = 1;
  f.vt[0] = 0;
  f.ut[2] = 0;
  f.vt[2] = 1;
  f.ut[1] = 1;
  f.vt[1] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);

  // left vertexes

  v.x = cubeSize;
  v.y = cubeSize;
  v.z = -cubeSize;
  m->addVert(v);

  v.x = cubeSize;
  v.y = cubeSize;
  v.z = cubeSize;
  m->addVert(v);

  v.x = cubeSize;
  v.y = -cubeSize;
  v.z = -cubeSize;
  m->addVert(v);
  
  v.x = cubeSize;
  v.y = -cubeSize;
  v.z = cubeSize;
  m->addVert(v);

  // left face - 1st part
  f.v[0] = 8;
  f.v[1] = 9;
  f.v[2] = 10;
  f.ut[0] = 0;
  f.vt[0] = 0;
  f.ut[1] = 1;
  f.vt[1] = 0;
  f.ut[2] = 0;
  f.vt[2] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);

  // left face - 2nd part
  f.v[0] = 9;
  f.v[1] = 11;
  f.v[2] = 10;
  f.ut[0] = 1;
  f.vt[0] = 0;
  f.ut[2] = 0;
  f.vt[2] = 1;
  f.ut[1] = 1;
  f.vt[1] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);

  // right vertexes

  v.x = -cubeSize;
  v.y = cubeSize;
  v.z = cubeSize;
  m->addVert(v);

  v.x = -cubeSize;
  v.y = cubeSize;
  v.z = -cubeSize;
  m->addVert(v);

  v.x = -cubeSize;
  v.y = -cubeSize;
  v.z = cubeSize;
  m->addVert(v);
  
  v.x = -cubeSize;
  v.y = -cubeSize;
  v.z = -cubeSize;
  m->addVert(v);

  // right face - 1st part
  f.v[0] = 12;
  f.v[1] = 13;
  f.v[2] = 14;
  f.ut[0] = 0;
  f.vt[0] = 0;
  f.ut[1] = 1;
  f.vt[1] = 0;
  f.ut[2] = 0;
  f.vt[2] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);

  // right face - 2nd part
  f.v[0] = 13;
  f.v[1] = 15;
  f.v[2] = 14;
  f.ut[0] = 1;
  f.vt[0] = 0;
  f.ut[2] = 0;
  f.vt[2] = 1;
  f.ut[1] = 1;
  f.vt[1] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);

  if ( cubeTopLess == false )
  {

      // top vertexes

      v.x = -cubeSize;
      v.y = cubeSize;
      v.z = cubeSize;
      m->addVert(v);

      v.x = cubeSize;
      v.y = cubeSize;
      v.z = cubeSize;
      m->addVert(v);

      v.x = -cubeSize;
      v.y = cubeSize;
      v.z = -cubeSize;
      m->addVert(v);
  
      v.x = cubeSize;
      v.y = cubeSize;
      v.z = -cubeSize;
      m->addVert(v);

      // top face - 1st part
      f.v[0] = 16;
      f.v[1] = 17;
      f.v[2] = 18;
      f.ut[0] = 0;
      f.vt[0] = 0;
      f.ut[1] = 1;
      f.vt[1] = 0;
      f.ut[2] = 0;
      f.vt[2] = 1;
      f.texture = s->getTexCount()-1;
      m->addFace(f);

      // top face - 2nd part
      f.v[0] = 17;
      f.v[1] = 19;
      f.v[2] = 18;
      f.ut[0] = 1;
      f.vt[0] = 0;
      f.ut[2] = 0;
      f.vt[2] = 1;
      f.ut[1] = 1;
      f.vt[1] = 1;
      f.texture = s->getTexCount()-1;
      m->addFace(f);

  }

  if ( cubeBottomLess == false )
  {

      // bottom vertexes

      v.x = -cubeSize;
      v.y = -cubeSize;
      v.z = -cubeSize;
      m->addVert(v);

      v.x = cubeSize;
      v.y = -cubeSize;
      v.z = -cubeSize;
      m->addVert(v);

      v.x = -cubeSize;
      v.y = -cubeSize;
      v.z = cubeSize;
      m->addVert(v);
  
      v.x = cubeSize;
      v.y = -cubeSize;
      v.z = cubeSize;
      m->addVert(v);

      // bottom face - 1st part
      f.v[0] = 20;
      f.v[1] = 21;
      f.v[2] = 22;
      f.ut[0] = 0;
      f.vt[0] = 0;
      f.ut[1] = 1;
      f.vt[1] = 0;
      f.ut[2] = 0;
      f.vt[2] = 1;
      f.texture = s->getTexCount()-1;
      m->addFace(f);

      // bottom face - 2nd part
      f.v[0] = 21;
      f.v[1] = 23;
      f.v[2] = 22;
      f.ut[0] = 1;
      f.vt[0] = 0;
      f.ut[2] = 0;
      f.vt[2] = 1;
      f.ut[1] = 1;
      f.vt[1] = 1;
      f.texture = s->getTexCount()-1;
      m->addFace(f);

  }

  strcpy(m->m_name, "Textured Cube");

  return true;
}

///////////////////////////////////////////////////////////////////////////////
// CObjects::createCylinder( ... )
///////////////////////////////////////////////////////////////////////////////
// Creates a cylinder using the texture specified in texname
///////////////////////////////////////////////////////////////////////////////
bool CObjects::createCylinder(CMeshStorage *s, const char *texname)
{
  float wk, x, y;
  float dTexX, texX;

  TMeshTriangle f;
  TMeshVertex v;

  CMeshData *m = s->getMesh(s->getMeshCount()-1);
  
  if (m == NULL)
      return false;

  m->clear();

  if ( fileHandler.loadImageToTexture(texname, &t1) == false )
  {      
      return false;
  }

  s->addTex(t1);

  dTexX = (float)(1.0) / (float)(cylinderCirclePoints-1);

  for (int k=0; k < cylinderCirclePoints-1; k++) {

	 wk = ((float)k * 360)/(cylinderCirclePoints-1);
     x = (float) (cylinderRadiusTop * cos(wk/180*M_PI));
     y = (float) (cylinderRadiusTop * sin(wk/180*M_PI));

     v.x = x;
     v.y = cylinderHeight;
     v.z = y;
        
     m->addVert(v);

  }

  for (int k=0; k < cylinderCirclePoints-1; k++) {

     wk = ((float)k * 360)/(cylinderCirclePoints-1);
     x = (float) (cylinderRadiusBottom * cos(wk/180*M_PI));
     y = (float) (cylinderRadiusBottom * sin(wk/180*M_PI));

     v.x = x;
     v.y = -cylinderHeight;
     v.z = y;
        
     m->addVert(v);

  }
  
  texX = 0;

  for (int k=0; k < cylinderCirclePoints-2; k++) {

      f.v[0] = k;
      f.v[1] = k+1;
      f.v[2] = k+cylinderCirclePoints-1;
      f.ut[0] = texX;
      f.vt[0] = 0;
      f.ut[1] = texX+dTexX;
      f.vt[1] = 0;
      f.ut[2] = texX;
      f.vt[2] = 1;
      f.texture = s->getTexCount()-1;
      m->addFace(f);
      
      f.v[0] = k+1;
      f.v[1] = k+cylinderCirclePoints+1-1;
      f.v[2] = k+cylinderCirclePoints-1;
      f.ut[0] = texX+dTexX;
      f.vt[0] = 0;
      f.ut[1] = texX+dTexX;
      f.vt[1] = 1;
      f.ut[2] = texX;
      f.vt[2] = 1;
      f.texture = s->getTexCount()-1;
      m->addFace(f);

      texX += dTexX;
  }

  int k = cylinderCirclePoints-2;
  
  f.v[0] = k;
  f.v[1] = 0;
  f.v[2] = k+cylinderCirclePoints-1;
  f.ut[0] = texX;
  f.vt[0] = 0;
  f.ut[1] = texX+dTexX;
  f.vt[1] = 0;
  f.ut[2] = texX;
  f.vt[2] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);
     
  f.v[0] = 0;
  f.v[1] = 0+cylinderCirclePoints+1-1-1;
  f.v[2] = k+cylinderCirclePoints-1;
  f.ut[0] = texX+dTexX;
  f.vt[0] = 0;
  f.ut[1] = texX+dTexX;
  f.vt[1] = 1;
  f.ut[2] = texX;
  f.vt[2] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);

  strcpy(m->m_name, "Textured Cylinder");

  return true;
}

///////////////////////////////////////////////////////////////////////////////
// CObjects::createCone( ... )
///////////////////////////////////////////////////////////////////////////////
// Creates a cone using the texture specified in texname
//
// If you prefer you can create a cone also with the createCylinder routine!
///////////////////////////////////////////////////////////////////////////////
bool CObjects::createCone(CMeshStorage *s, const char *texname)
{
  float wk, x, y;
  float dTexX, texX;
  
  TMeshTriangle f;
  TMeshVertex v;

  CMeshData *m = s->getMesh(s->getMeshCount()-1);
  
  if (m == NULL)
      return false;

  m->clear();

  if ( fileHandler.loadImageToTexture(texname, &t1) == false )
  {      
      return false;
  }

  s->addTex(t1);

  dTexX = (float)(1.0) / (float)(coneCirclePoints-1);
  
  for (int k=0; k < coneCirclePoints-1; k++) {

     wk = ((float)k * 360)/(coneCirclePoints-1);
     x = (float) (0 * cos(wk/180*M_PI));
     y = (float) (0 * sin(wk/180*M_PI));

     v.x = x;
     v.y = coneHeight;
     v.z = y;
        
     m->addVert(v);

  }

  for (int k=0; k < coneCirclePoints-1; k++) {

     wk = ((float)k * 360)/(coneCirclePoints-1);
     x = (float) (coneRadiusBottom * cos(wk/180*M_PI));
     y = (float) (coneRadiusBottom * sin(wk/180*M_PI));

     v.x = x;
     v.y = -coneHeight;
     v.z = y;
        
     m->addVert(v);

  }
  
  texX = 0;

  for (int k=0; k < coneCirclePoints-2; k++) {

      f.v[0] = k;
      f.v[1] = k+1;
      f.v[2] = k+coneCirclePoints-1;
      f.ut[0] = texX;
      f.vt[0] = 0;
      f.ut[1] = texX+dTexX;
      f.vt[1] = 0;
      f.ut[2] = texX;
      f.vt[2] = 1;
      f.texture = s->getTexCount()-1;
      m->addFace(f);
      
      f.v[0] = k+1;
      f.v[1] = k+coneCirclePoints+1-1;
      f.v[2] = k+coneCirclePoints-1;
      f.ut[0] = texX+dTexX;
      f.vt[0] = 0;
      f.ut[1] = texX+dTexX;
      f.vt[1] = 1;
      f.ut[2] = texX;
      f.vt[2] = 1;
      f.texture = s->getTexCount()-1;
      m->addFace(f);

      texX += dTexX;
  }

  int k = coneCirclePoints-2;
  
  f.v[0] = k;
  f.v[1] = 0;
  f.v[2] = k+coneCirclePoints-1;
  f.ut[0] = texX;
  f.vt[0] = 0;
  f.ut[1] = texX+dTexX;
  f.vt[1] = 0;
  f.ut[2] = texX;
  f.vt[2] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);
     
  f.v[0] = 0;
  f.v[1] = 0+coneCirclePoints+1-1-1;
  f.v[2] = k+coneCirclePoints-1;
  f.ut[0] = texX+dTexX;
  f.vt[0] = 0;
  f.ut[1] = texX+dTexX;
  f.vt[1] = 1;
  f.ut[2] = texX;
  f.vt[2] = 1;
  f.texture = s->getTexCount()-1;
  m->addFace(f);

  strcpy(m->m_name, "Textured Cone");

  return true;
}

///////////////////////////////////////////////////////////////////////////////
// CObjects::createSphere( ... )
///////////////////////////////////////////////////////////////////////////////
// Creates a sphere using the texture specified in texname
///////////////////////////////////////////////////////////////////////////////
bool CObjects::createSphere(CMeshStorage *s, const char *texname)
{
  float kr=(float)sphereRadius;
  float kp=(float)spherePoints;
  float ks=(float)sphereVCircles;
  float wk,x,y,r;
  float radius[999];
  float dx, dy;

  TMeshVertex v;
  TMeshTriangle t;

  CMeshData *m = s->getMesh(s->getMeshCount()-1);

  if (m == NULL)
	  return false;

  m->clear();

  if ( fileHandler.loadImageToTexture(texname, &t1) == false )
  {
	  return false;
  }

  s->addTex(t1);

  dx = (float)(1.0) / (float)(kp-1);
  dy = (float)(1.0) / (float)((ks*2));

  // precalculate the radius on the different horizontal circles
  for(int w=0; w<=((int)ks-1); w++) {

    wk = w*90/(ks-1);
    radius[w] = (float) (kr*sin(wk/180*M_PI));

  }

  // Calc. the vetexes in the upper sphere
  for(int j=0; j<=((int)ks-1); j++) {

    r = radius[j];

    for(int k=0; k<=((int)kp-1); k++) {

        wk = k * 360/(kp-1);
        x = (float) (r*cos(wk/180*M_PI));
        y = (float) (r*sin(wk/180*M_PI));

		v.x = x;
        v.y = +radius[((int)ks-1)-j];
        v.z = y;
        
		m->addVert(v);

    }
  }

  // Calc. the vetexes in the lower sphere
  for(int j=1; j<=((int)ks-1); j++) {

	r = radius[((int)ks-1)-j];
    
    for(int k=0; k<=((int)kp-1); k++) {

        wk = k * 360/(kp-1);
        x = (float) (r*cos(wk/180*M_PI));
        y = (float) (r*sin(wk/180*M_PI));

        v.x = x;
        v.y = -radius[j];
        v.z = y;

		m->addVert(v);

    }
  }

  // Connect the vetexes
  for(int j=1; j<=(((int)ks-1)*2); j++) {

    for(int k=0; k<=((int)kp-2); k++) {

      // Faces from k to k+1 to k+kp
      int b=(j-1)*((int)kp)+1;
	  t.v[0] = (b+k);
      if(k!=((int)kp-2)) t.v[1]=(b+k+1);
      if(k==((int)kp-2)) t.v[1]=(b);
      t.v[2]=(b+k+((int)kp));

      t.texture = s->getTexCount()-1;

      t.ut[0] = (float)(dx*(float)(k));
      t.vt[0] = (float)(dy*(float)(j));
      if(k!=((int)kp-2))
      {
         t.ut[1] = (float)(dx*(float)(k+1));
         t.vt[1] = (float)(dy*(float)(j));
      }
      if(k==((int)kp-2))
      {
         t.ut[1] = (float)(dx*(k+1));
         t.vt[1] = (float)(dy*(float)(j));
      }
      t.ut[2] = (float)(dx*(float)k);
      t.vt[2] = (float)(dy*(float)(j+1));

      m->addFace(t);

      // Faces from k+1 to k+1+kp to k+kp
      if(k!=((int)kp-2)) t.v[0]=(b+k+1);
      if(k==((int)kp-2)) t.v[0]=(b);
      if(k!=((int)kp-2)) t.v[1]=(b+k+((int)kp)+1);
      if(k==((int)kp-2)) t.v[1]=(b+((int)kp));
      t.v[2]=b+k+((int)kp);

      t.texture = s->getTexCount()-1;

      if(k!=((int)kp-2))
      {
        t.ut[0] = (float)(dx*(float)(k+1));
        t.vt[0] = (float)(dy*(float)(j));
      }
      if(k==((int)kp-2))
      {
        t.ut[0] = (float)(dx*(float)(k+1));
        t.vt[0] = (float)(dy*(float)(j));
      }
      if(k!=((int)kp-2))
      {
        t.ut[1] = (float)(dx*(float)(k+1));
        t.vt[1] = (float)(dy*(float)(j+1));
      }
      if(k==((int)kp-2))
      {
        t.ut[1] = (float)(dx*(float)(k+1));
        t.vt[1] = (float)(dy*(float)(j+1));
      }
      t.ut[2] = (float)(dx*(float)(k));
      t.vt[2] = (float)(dy*(float)(j+1));

      m->addFace(t);
    }
  }

  strcpy(m->m_name, "Textured Sphere");

  return true;
}

///////////////////////////////////////////////////////////////////////////////
// CObjects::createHeightmap( ... )
///////////////////////////////////////////////////////////////////////////////
// Creates a height map with a few sinus & cosinus operations
///////////////////////////////////////////////////////////////////////////////
bool CObjects::createHeightMap(THeightMap *h, int xSize, int zSize)
{
   int x, z;
   float height;
   float seed = simpleSurfaceSeed;

   h->xSize = xSize;
   h->zSize = zSize;

   for(x = 0; x < xSize; x++)
   {
       for(z = 0; z < zSize; z++)
       {
           seed = (float)(((int)(seed*10421+1)) % (int)65536);
           height = seed / 256;
           
           h->map[x][z] = height;
       }
   }

   return true;
}

///////////////////////////////////////////////////////////////////////////////
// CObjects::smoothHeightmap( ... )
///////////////////////////////////////////////////////////////////////////////
// Smoothes a height map with bilinear filter
///////////////////////////////////////////////////////////////////////////////
bool CObjects::smoothHeightMap(THeightMap *h)
{
   int x, z, n;
   float height;

   for(x = 0; x < h->xSize; x++)
   {
       for(z = 0; z < h->zSize; z++)
       {
           n=0;
           height = 0;

           if (x > 0)
           {
               height = height + h->map[x-1][z];
               n++;
           }
           if (x < h->xSize-1)
           {
               height = height + h->map[x+1][z];
               n++;
           }
           if (z > 0)
           {
               height = height + h->map[x][z-1];
               n++;
           }
           if (z < h->zSize-1)
           {
               height = height + h->map[x][z+1];
               n++;
           }
           
           h->map[x][z] = height/n;
       }
   }
   
   return true;
}

///////////////////////////////////////////////////////////////////////////////
// CObjects::normalizeHeightmap( ... )
///////////////////////////////////////////////////////////////////////////////
// Normalize a height map
///////////////////////////////////////////////////////////////////////////////
bool CObjects::normalizeHeightMap(THeightMap *h)
{
   int x, z;
   float height;
   float min, max;
   
   min = 255;
   max = 0;

   for(x = 0; x < h->xSize; x++)
   {
       for(z = 0; z < h->zSize; z++)
       {
           height = h->map[x][z];
           
           if (height > max)
               max = height;
           if (height < min)
               min = height;
       }
   }

   for(x = 0; x < h->xSize; x++)
   {
       for(z = 0; z < h->zSize; z++)
       {
           height = h->map[x][z];
           
           height = height - min;
           height = height * 255 / (max-min);
           
           h->map[x][z] = height;
       }
   }
   
   return true;
}

///////////////////////////////////////////////////////////////////////////////
// CObjects::scalingHeightMap( ... )
///////////////////////////////////////////////////////////////////////////////
// Scales a height map
///////////////////////////////////////////////////////////////////////////////
bool CObjects::scalingHeightMap(THeightMap *h, float scalingLevel)
{
   int x, z;

   for(x = 0; x < h->xSize; x++)
   {
       for(z = 0; z < h->zSize; z++)
       {
           h->map[x][z] = h->map[x][z] / scalingLevel;           
       }
   }
   
   return true;
}

///////////////////////////////////////////////////////////////////////////////
// CObjects::createSimpleSurface( ... )
///////////////////////////////////////////////////////////////////////////////
// Creates a surface using the given textures
// 
// Caution: A height map with a size of x*z has (x-1)*(z-1)*2 triangles!
//
// ==> 32x32 =  1922 triangles
// ==> 64x64 =  7938 triangles
// ==> 96x96 = 18050 triangles
///////////////////////////////////////////////////////////////////////////////
bool CObjects::createSimpleSurface(CMeshStorage *s, const char *texname, const char *texname2,
                                   const char *texname3, const char *texname4, const char *texname5)
{
  bool deepWater1, deepWater2;
  float mtpl;
  int x,z,i;
  unsigned int pLU, pLB, pRU, pRB;

  THeightMap    hMap, hMapCopy;
  TMeshTriangle f;
  TMeshVertex   v;
  
  CMeshData *m = s->getMesh(s->getMeshCount()-1);
  
  if (m == NULL)
      return false;

  // Create a surface map
  createHeightMap(&hMap, simpleSurfaceSizeX, simpleSurfaceSizeZ);
  // Smooth the surface map
  for( i=0; i<simpleSurfaceSmoothLevel; i++)
      smoothHeightMap(&hMap);
  // Normalize the surface map
  normalizeHeightMap(&hMap);
  // Scaling the surface map
  scalingHeightMap(&hMap, simpleSurfaceScaling);
  
  // Load the first texture
  m->clear();

  if ( fileHandler.loadImageToTexture(texname, &t1) == false )
  {      
      return false;
  }

  s->addTex(t1);
  
  // Load the second texture
  m->clear();

  if ( fileHandler.loadImageToTexture(texname2, &t1) == false )
  {      
      return false;
  }

  s->addTex(t1);
  
  // Load the third texture
  m->clear();

  if ( fileHandler.loadImageToTexture(texname3, &t1) == false )
  {      
      return false;
  }

  s->addTex(t1);
  
  // Load the fourth texture
  m->clear();

  if ( fileHandler.loadImageToTexture(texname4, &t1) == false )
  {      
      return false;
  }

  s->addTex(t1);
  
  // Load the fifth texture
  m->clear();

  if ( fileHandler.loadImageToTexture(texname5, &t1) == false )
  {      
      return false;
  }

  s->addTex(t1);
  
  hMapCopy.xSize = hMap.xSize;
  hMapCopy.zSize = hMap.zSize;

  for(x = 0; x < hMap.xSize; x++)
  {
      for(z = 0; z < hMap.zSize; z++)
      {
           hMapCopy.map[x][z] = hMap.map[x][z];
      }
  }
   
  // How to extend the x/z-axis
  mtpl = simpleSurfaceMultiplikator;
  
  for(x = 0; x < hMap.xSize; x++)
  {
      for(z = 0; z < hMap.zSize; z++)
      {

          if ( (hMap.map[x][z] <= simpleSurfaceWaterLevel) )
                hMapCopy.map[x][z] = simpleSurfaceWaterLevel;
          
          v.x = mtpl*x;
          v.y = hMapCopy.map[x][z];
          v.z = mtpl*z;
          m->addVert(v);
	  }
  }

  float fakx = 1 / (float) hMap.xSize;
  float fakz = 1 / (float) hMap.zSize;

  for(x = 0; x < hMap.xSize-1; x++)
  {
      for(z = 0; z < hMap.zSize-1; z++)
      {
          pLU = (x+1)*hMap.zSize+(z+1);
          pRU = (x)*hMap.zSize+(z+1);
          pLB = (x+1)*hMap.zSize+(z);
          pRB = (x)*hMap.zSize+(z);

          if ( (hMap.map[x][z+1] <= simpleSurfaceDeepWaterLevel) &&
               (hMap.map[x+1][z] <= simpleSurfaceDeepWaterLevel) &&
               (hMap.map[x+1][z+1] <= simpleSurfaceDeepWaterLevel) )
                deepWater1 = true;
          else
                deepWater1 = false;
          if ( (hMap.map[x][z] <= simpleSurfaceDeepWaterLevel) &&
               (hMap.map[x][z+1] <= simpleSurfaceDeepWaterLevel) &&
               (hMap.map[x+1][z] <= simpleSurfaceDeepWaterLevel) )
                deepWater2 = true;
          else
                deepWater2 = false;
               
          f.v[0] = pLU;
          f.v[1] = pLB;
		  f.v[2] = pRU;

		  /*
           * f.ut[0] = 0;
           * f.vt[0] = 0;
           * f.ut[1] = 0;
           * f.vt[1] = 1;
           * f.ut[2] = 1;
           * f.vt[2] = 0;
		   */

          f.ut[0] = (x+1) * fakx;
          f.vt[0] = (z+1) * fakz;
          f.ut[1] = (x+1) * fakx;
          f.vt[1] = (z) * fakz;
          f.ut[2] = (x) * fakx;
          f.vt[2] = (z+1) * fakz;
          if ( (hMap.map[x][z+1] <= simpleSurfaceWaterLevel) &&
               (hMap.map[x+1][z] <= simpleSurfaceWaterLevel) &&
               (hMap.map[x+1][z+1] <= simpleSurfaceWaterLevel) )
                if ( deepWater1 )
                     f.texture = s->getTexCount()-1;
                else 
                     f.texture = s->getTexCount()-2;
          else
             if ( (hMap.map[x][z+1] > simpleSurfaceSnowLevel) &&
                  (hMap.map[x+1][z] > simpleSurfaceSnowLevel) &&
                  (hMap.map[x+1][z+1] > simpleSurfaceSnowLevel) )
                 f.texture = s->getTexCount()-5;
             else
                if ( (hMap.map[x][z+1] < simpleSurfaceBeachLevel) &&
                     (hMap.map[x+1][z] < simpleSurfaceBeachLevel) &&
                     (hMap.map[x+1][z+1] < simpleSurfaceBeachLevel) )
                    f.texture = s->getTexCount()-3;
                else
                    f.texture = s->getTexCount()-4;
          m->addFace(f);

          f.v[0] = pRU;
          f.v[1] = pLB;
          f.v[2] = pRB;

		  /*
           * f.ut[0] = 1;
           * f.vt[0] = 0;
           * f.ut[1] = 0;
           * f.vt[1] = 1;
           * f.ut[2] = 1;
           * f.vt[2] = 1;
		   */

          f.ut[0] = (x) * fakx;
          f.vt[0] = (z+1) * fakz;
          f.ut[1] = (x+1) * fakx;
          f.vt[1] = (z) * fakz;
          f.ut[2] = (x) * fakx;
          f.vt[2] = (z) * fakz;
          if ( (hMap.map[x][z] <= simpleSurfaceWaterLevel) &&
               (hMap.map[x][z+1] <= simpleSurfaceWaterLevel) &&
               (hMap.map[x+1][z] <= simpleSurfaceWaterLevel) )
                if ( deepWater2 )
                     f.texture = s->getTexCount()-1;
                else 
                     f.texture = s->getTexCount()-2;
          else
             if ( (hMap.map[x][z] > simpleSurfaceSnowLevel) &&
                  (hMap.map[x][z+1] > simpleSurfaceSnowLevel) &&
                  (hMap.map[x+1][z] > simpleSurfaceSnowLevel) )
                   f.texture = s->getTexCount()-5;
             else
                if ( (hMap.map[x][z] < simpleSurfaceBeachLevel) &&
                     (hMap.map[x][z+1] < simpleSurfaceBeachLevel) &&
                     (hMap.map[x+1][z] < simpleSurfaceBeachLevel) )
                    f.texture = s->getTexCount()-3;
                else
                    f.texture = s->getTexCount()-4;
          m->addFace(f);
       }
  }

  strcpy(m->m_name, "Textured Simple Surface");

  return true;
}

///////////////////////////////////////////////////////////////////////////////
// CObjects::getRGBColor( ... )
///////////////////////////////////////////////////////////////////////////////
TRGBColorTriple CObjects::getRGBColor(unsigned int c)
{
  TRGBColorTriple tRGB;

  tRGB.r = (unsigned int) (c & 0xFF);
  tRGB.g = (unsigned int) ((c>>8) & 0xFF);
  tRGB.b = (unsigned int) ((c>>16) & 0xFF);

  return tRGB;
}

bool CObjects::createHeightMapSurface(CMeshStorage *s, const char *hmname, const char *texname)
{
  float mtpl, mtply;
  int x,y;
  unsigned int pLU, pLB, pRU, pRB;
  TMeshTriangle   f;
  TMeshVertex	  v;
  TRGBColorTriple tRGB;

  CMeshData *m = s->getMesh(s->getMeshCount()-1);
  
  if (m == NULL)
      return false;

  // Load the texture
  m->clear();

  if ( fileHandler.loadImageToPicture(hmname, &p1) == false )
	  return false;

  if ( fileHandler.loadImageToTexture(texname, &t1) == false )
	  return false;

  s->addTex(t1);

  mtpl = heightMapSurfaceMultiplikator;
  mtply = heightMapSurfaceMultiplikatorY;

  if ( heightMapSurfaceAutoBalance == 1 )
  {
	  if ( (p1.sizeX < 128) || (p1.sizeX < 128) )
	  {
		  mtpl = (float) (256 * 5 / p1.sizeX);
	  }
  }

  // Now convert the picture's height data to vertexes
  for (x=0; x<p1.sizeX; x++)
  {
	 for (y=0; y<p1.sizeY; y++)
     {
		 tRGB = getRGBColor(p1.rgb[y*p1.sizeX+x]);
		  
          v.x = mtpl*x;
          v.y = mtply*((tRGB.r+tRGB.g+tRGB.b)/3);
          v.z = mtpl*y;

          m->addVert(v);
	}
  }

  float fakx = 1 / (float) p1.sizeX;
  float faky = 1 / (float) p1.sizeY;

  for (x=0; x<p1.sizeX-1; x++)
  {
	 for (y=0; y<p1.sizeY-1; y++)
     {

          pLU = (x+1)*p1.sizeY+(y+1);
          pRU = (x)*p1.sizeY+(y+1);
          pLB = (x+1)*p1.sizeY+(y);
          pRB = (x)*p1.sizeY+(y);
               
          f.v[0] = pLU;
          f.v[1] = pLB;
          f.v[2] = pRU;
          f.ut[0] = (x+1) * fakx;
          f.vt[0] = (y+1) * faky;
          f.ut[1] = (x+1) * fakx;
          f.vt[1] = (y) * faky;
          f.ut[2] = (x) * fakx;
          f.vt[2] = (y+1) * faky;
          f.texture = s->getTexCount()-1;
          m->addFace(f);

          f.v[0] = pRU;
          f.v[1] = pLB;
          f.v[2] = pRB;
          f.ut[0] = (x) * fakx;
          f.vt[0] = (y+1) * faky;
          f.ut[1] = (x+1) * fakx;
          f.vt[1] = (y) * faky;
          f.ut[2] = (x) * fakx;
          f.vt[2] = (y) * faky;
          f.texture = s->getTexCount()-1;
		  m->addFace(f);
	 }
  }

  strcpy(m->m_name, "Textured HeightMap Surface");

  return true;
}
